import logging
from pathlib import Path
import argparse

from .utils import (
    create_query_list_with_intrinsics, scale_sfm_images, evaluate)
from ... import extract_features, match_features, pairs_from_covisibility
from ... import triangulation, localize_sfm, pairs_from_retrieval

SCENES = ['KingsCollege', 'OldHospital', 'ShopFacade', 'StMarysChurch',
          'GreatCourt']


def run_scene(images, gt_dir, outputs, results, num_covis, num_loc):
    ref_sfm_sift = gt_dir / 'model_train'
    test_list = gt_dir / 'list_query.txt'

    outputs.mkdir(exist_ok=True, parents=True)
    ref_sfm = outputs / 'sfm_superpoint+superglue'
    ref_sfm_scaled = outputs / 'sfm_sift_scaled'
    query_list = outputs / 'query_list_with_intrinsics.txt'
    sfm_pairs = outputs / f'pairs-db-covis{num_covis}.txt'
    loc_pairs = outputs / f'pairs-query-netvlad{num_loc}.txt'

    feature_conf = {
        'output': 'feats-superpoint-n4096-r1024',
        'model': {
            'name': 'superpoint',
            'nms_radius': 3,
            'max_keypoints': 4096,
        },
        'preprocessing': {
            'grayscale': True,
            'resize_max': 1024,
        },
    }
    matcher_conf = match_features.confs['superglue']
    retrieval_conf = extract_features.confs['netvlad']

    create_query_list_with_intrinsics(
            gt_dir / 'empty_all', query_list, test_list,
            ext='.txt', image_dir=images)
    with open(test_list, 'r') as f:
        query_seqs = {q.split('/')[0] for q in f.read().rstrip().split('\n')}

    global_descriptors = extract_features.main(retrieval_conf, images, outputs)
    pairs_from_retrieval.main(
        global_descriptors, loc_pairs, num_loc,
        db_model=ref_sfm_sift, query_prefix=query_seqs)

    features = extract_features.main(
            feature_conf, images, outputs, as_half=True)
    pairs_from_covisibility.main(
            ref_sfm_sift, sfm_pairs, num_matched=num_covis)
    sfm_matches = match_features.main(
            matcher_conf, sfm_pairs, feature_conf['output'], outputs)

    scale_sfm_images(ref_sfm_sift, ref_sfm_scaled, images)
    triangulation.main(
        ref_sfm, ref_sfm_scaled,
        images,
        sfm_pairs,
        features,
        sfm_matches,
        colmap_path='colmap')

    loc_matches = match_features.main(
        matcher_conf, loc_pairs, feature_conf['output'], outputs)

    localize_sfm.main(
        ref_sfm,
        query_list,
        loc_pairs,
        features,
        loc_matches,
        results,
        covisibility_clustering=False,
        prepend_camera_name=True)


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--scenes', default=SCENES, choices=SCENES, nargs='+')
    parser.add_argument('--overwrite', action='store_true')
    parser.add_argument('--dataset', type=Path, default='datasets/cambridge',
                        help='Path to the dataset, default: %(default)s')
    parser.add_argument('--outputs', type=Path, default='outputs/cambridge',
                        help='Path to the output directory, default: %(default)s')
    parser.add_argument('--num_covis', type=int, default=20,
                        help='Number of image pairs for SfM, default: %(default)s')
    parser.add_argument('--num_loc', type=int, default=50,
                        help='Number of image pairs for loc, default: %(default)s')
    args = parser.parse_args()

    gt_dirs = args.dataset / 'CambridgeLandmarks_Colmap_Retriangulated_1024px'

    all_results = {}
    for scene in args.scenes:
        logging.info(f'Working on scene "{scene}".')
        results = args.outputs / scene / 'results.txt'
        if args.overwrite or not results.exists():
            run_scene(
                args.dataset / scene,
                gt_dirs / scene,
                args.outputs / scene,
                results,
                args.num_covis,
                args.num_loc)
        all_results[scene] = results

    for scene in args.scenes:
        logging.info(f'Evaluate scene "{scene}".')
        evaluate(
            gt_dirs / scene / 'empty_all', all_results[scene],
            gt_dirs / scene / 'list_query.txt', ext='.txt')
